package com.xixibaby.core;

import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ReferenceUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author : tomj
 * V.init(a,ne).throwBusExcepttion("")
 * W.succ(data,"").filter;
 * W.model()
 * W.fail("")
 * W.exception()
 * @Date: 2019-02-14 13:41
 * @Description:
 */
@Slf4j
public class Assert<T> {

    private final boolean isPresent;

    private Assert(T value, Predicate<T> predicate) {
        this.isPresent =  predicate.test(value);
    }

    /**
     * 初始化验证
     * @param value 需要验证的对象
     * @param predicate  验证规则
     * @param <T>
     * @return
     */
    public static<T> Assert<T> init(T value, Predicate<T> predicate) {
        return new Assert(value,predicate);
    }


    /**
     * 一般 验证 会通过的验证 参考NE
     * @param value  需要验证的对象
     * @param <T>
     * @return
     */
    public static<T> Assert<T> succ(T value) {
        return init(value, Assert::notEmpty);
    }

    public static<T> Assert<T> fail(T value) {
        return init(value, $->!notEmpty($));
    }


    private<X extends Throwable> void thenThrow(Function<String,X> exf, String msg) throws X{
        throw exf.apply(msg);
    }



    private<X extends Throwable> void thenThrow(Supplier<X> exf) throws X{
        throw exf.get();
    }

    /**
     * 当且仅当验证失败 才会抛{@code BusException}出异常
     * @param msg
     * @param <X>
     * @return
     * @throws X
     */
    public<X extends Throwable> void thenThrow(String msg){
        if (!isPresent) {
            this.thenThrow(BusException::new,msg);
        }
    }

    public<X extends Throwable> void thenThrow(Integer code,String msg){
        if (!isPresent) {
            this.thenThrow(x -> new BusException(code,msg),msg);
        }
    }

    public<X extends Throwable> void thenThrow(String msg,Object... objects){
        if (!isPresent) {
            this.thenThrow(BusException::new,StrUtil.format(msg,objects));
        }
    }

    public<X extends Throwable> void thenThrowAuthException(){
        if (!isPresent) {
            this.thenThrow(AuthException::new);
        }
    }


    public<X extends Throwable> void thenThrowAndMsg(String target,String msg,Supplier<Object> supplier,Object... objects){
        this.thenThrowAndMsg(target,StrUtil.format(msg,objects),supplier);
    }

    public<X extends Throwable> void thenThrowAndMsg(String msg,Supplier<Object> supplier,Object... objects){
        this.thenThrowAndMsg("",StrUtil.format(msg,objects),supplier);
    }

    public<X extends Throwable> void thenThrowAndMsg(String msg,Supplier<Object> supplier){
        this.thenThrowAndMsg("",msg,supplier);
    }



    public<X extends Throwable> void thenThrowAndMsg(String target,String msg,Supplier<Object> supplier){
        if (!isPresent) {
            this.thenThrow(() -> new SelectException(target,msg,supplier));
        }
    }

    public<X extends Throwable> void thenMessage(String msg,Supplier<Object> supplier,Object... objects){
        this.thenMessage(StrUtil.format(msg,objects),supplier);
    }

    public<X extends Throwable> void thenMessage(String msg,Object... objs){
        this.thenMessage(StrUtil.format(msg,objs));
    }

    public<X extends Throwable> void thenMessage(String msg){
        if (!isPresent) {
//            try {
//                //
//                MessageService dingdingService = SpringUtil.getBean("dingdingService");
//                Class<?> aClass = Class.forName("com.xixibaby.message.channel.dingding.DDMessage");
//                Object o = ReflectUtil.newInstance(aClass, StrUtil.format("异常消息：[{}]",msg));
//                dingdingService.sendMsg("",  o );
//            } catch (ClassNotFoundException | NoSuchBeanDefinitionException e) {
//                this.thenLogError("无法发送钉钉消息，未安装钉钉消息插件");
//            }
            this.thenLogError(msg);
        }
    }



    public<X extends Throwable> void thenDefault(Supplier<Object> supplier){
        if (!isPresent) {
            this.thenThrow(() -> new DefaultException(supplier));
        }
    }


    public<X extends Throwable> void thenThrowException(){
        if (!isPresent) {
            this.thenThrow(AuthException::new);
        }
    }



    public<X extends Throwable> void thenLogError(String msg){
        if (!isPresent) {
            log.error(msg);
        }
    }


    private static<T> boolean email(T str){
        return Validator.isEmail(str.toString());
    }

    /**
     * NOT EMPTY
     * 验证非空
     * 包括 "" ''  String
     * 长度为0的list  Collect
     * 没有key的map   map
     * 为0 的Integer Long Double
     * boolean 的 false
     * 长度为0 的数组
     * @param str  ""
     * @return 非空
     */
    public static<T> boolean notEmpty(T str){
        if(null == str) {return false;}

        if(str instanceof String){
            String string = (String)str;
            return StrUtil.isNotBlank(string);
        }else if(str instanceof List){
            return  !((List)str).isEmpty();
        }else if(str instanceof Map){
            return !((Map)str).isEmpty();
        }else if(str instanceof Integer){
            return ((Integer) str) != 0;
        }else if(str instanceof Long){
            return ((Long) str) != 0L;
        }else if(str instanceof Double){
            return ((Double) str) != 0D;
        }else if(str.getClass().isArray()){
            return ((Object[])str).length != 0;
        }else if(str instanceof Boolean){
            return ((Boolean)str);
        } else {
            return Objects.nonNull(str);
        }
    }

    public static<T> boolean empty(T str){
        return !notEmpty(str);
    }

    public static boolean hasChinese(String str){
        String regEx = "[\\u4e00-\\u9fa5]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        while (m.find()) {
            return true;
        }
        return false;
    }

    /**
     * Date is before
     * @param start
     * @param end
     * @param addOneDay
     * @return
     */
    public static boolean dateIsBefore(String start, String end, boolean addOneDay){
        if(!Assert.notEmpty(start)) {return false;}
        if(!Assert.notEmpty(end)) {return false;}
        LocalDate e = LocalDate.parse(end);
        if(addOneDay){
            e = e.plusDays(1);
            end = e.toString();
        }
        return LocalDate.parse(start).isBefore(e);
    }

    /**
     * Datetime is befor
     * @param start
     * @param end
     * @param addOneDay
     * @return
     */
    public static boolean dateTimeIsBefore(String start, String end, boolean addOneDay){
        if(!Assert.notEmpty(start)) {return false;}
        if(!Assert.notEmpty(end)) {return false;}
        LocalDateTime e = LocalDateTime.parse(end);
        if(addOneDay){
            e = e.plusDays(1);
        }
        return LocalDateTime.parse(start).isBefore(e);
    }

    public static boolean decimalIsBefore(BigDecimal start, BigDecimal end, boolean add){
        if(!Assert.notEmpty(start)) {return false;}
        if(!Assert.notEmpty(end)) {return false;}
        if(add){
            end = end.add(new BigDecimal(0.01));
        }
        return start.compareTo(end) < 0;
    }

    public static boolean notHasChinese(String str){
        return !hasChinese(str);
    }

    public static boolean isAccount(String account){
        return Validator.isMactchRegex("^[a-zA-Z0-9]{6,20}$", account);
    }

    public static boolean isPassword(String password){
        if(password.contains(" ")) {
            return false;
        }

        if(password.length() > 10 || password.length() < 6){
            return false;
        }
        return true;
    }

    public static void main(String[] args) {
        //boolean mactchRegex = Validator.isMactchRegex("^[a-zA-Z0-9\\~\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)]{1,10}$", "xiying1224!*&xiying1224xiying1224");
        System.out.println(isPassword("java12346"));
    }

}
